package com.media.module.widget;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

import com.media.module.interfaces.AudioStater;
import com.media.module.interfaces.IVisualizer;
import com.media.module.interfaces.MediaRecordFuncStater;
import com.media.module.utils.AudioUtils;
import com.media.module.utils.CameraUtils;
import com.media.module.utils.MediaRecordFunc;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

/**
 * Created by firezenk on 14/11/15.
 */
@SuppressWarnings("unused")
public class Visualizer extends LinearLayout implements IVisualizer,MediaRecordFuncStater {
	/**
	 * 构造时候需要的Activity，主要用于获取文件夹的路径
	 */
	
	private Activity activity;
	/**
	 * 录音状态
	 */
	private boolean isRecording = false;
	private int FORMAT = 1;
	private int VISUALIZER_WIDTH = 200;
	private int VISUALIZER_HEIGHT = 400;
	private int VISUALIZER_NUM_WAVES = 15;
	private int VISUALIZER_GRAVITY = 2;
	private String amrPath = "";
	private int LINE_WIDTH = 20;
	private int LINE_MIN_WIDTH = 20;
	private int LINE_HEIGHT = 20;
	private int LINE_MIN_HEIGHT = 20;
	private int LINE_SPACING = 10;
	private int LINE_BORDER_RADIUS = 50;
	private int BALL_DIAMETER = 20;
	private static final int INT_VISUALIZER = 1;
	private int COLOR_UNIFORM = android.R.color.black;
	private boolean COLOR_IS_GRADIENT = true;
	private int COLOR_GRADIENT_START = android.R.color.white;
	private int COLOR_GRADIENT_END = android.R.color.black;
	private String AUDIO_PATH_ONE = "";
	private String AUDIO_PATH_TWO = "";
	private String AUDIO_PATH_THREE = "";
	private static final String STR_AMR = ".amr";
	private String mstrPath = "";
	private MediaRecordFunc mMediaRecordFunc;
	private AudioStater mAudioStater;
	@SuppressLint("HandlerLeak")
	private Handler uiThread = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			if (msg.what == INT_VISUALIZER) {
				waveList.get(msg.arg2 - 1).setLayoutParams((LinearLayout.LayoutParams) msg.obj);
			}

		}

	};

	private Context context;
	private Random randomNum = new Random();
	private LinearLayout.LayoutParams params;
	private ArrayList<View> waveList = new ArrayList<View>();

	public Visualizer(Context context) {
		super(context);
		this.context = context;
		if (!isInEditMode()) {
			this.attributes();
			this.init();
		}
	}

	public Visualizer(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;

		if (!isInEditMode()) {
			this.attributes();
			this.init();
		}
	}

	public void setAudioStater(AudioStater audioStater) {
		this.mAudioStater = audioStater;
	}

	public void setInitData(Activity activity, String path) {
		this.activity = activity;
		mstrPath = path;
		this.amrPath = mstrPath + "AUDIO_" + CameraUtils.getModifyTime() + STR_AMR;
	}

	@SuppressLint("NewApi")
	public Visualizer(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		this.context = context;

		if (!isInEditMode()) {
			this.attributes();
			this.init();
		}
	}

	private void attributes() {
		/**
		 * 样式 <attr name="aw_format" format="enum"> <enum name="horizonal_lines"
		 * value="0"/> <enum name="horizontal_balls" value="1"/> <enum name=
		 * "vertical_lines" value="2"/> <enum name="vertical_balls" value="3"/>
		 * </attr>
		 */
		FORMAT = 2;
		// 高度
		VISUALIZER_HEIGHT = 400;
		// 宽度
		VISUALIZER_WIDTH = 200;
		// 圆个数
		VISUALIZER_NUM_WAVES = 30;
		/**
		 * 空间位置
		 * <attr name="aw_gravity" format="enum"> <enum name="center" value=
		 * "0"/> <enum name="left" value="1"/> <enum name="top" value="2"/>
		 * <enum name="right" value="3"/> <enum name="bottom" value="4"/>
		 * </attr>
		 */
		VISUALIZER_GRAVITY = 0;
		/**
		 * 线宽度
		 */
		LINE_WIDTH = 50;
		/**
		 * 线最小宽度
		 */
		LINE_MIN_WIDTH = 50;
		/**
		 * 线高度
		 */
		LINE_HEIGHT = 30;
		/**
		 * 线最小高度
		 */
		LINE_MIN_HEIGHT = 1;
		/**
		 * 线间隔
		 */
		LINE_SPACING = 0;
		// 线的上浮下线
		LINE_BORDER_RADIUS = 100;
		// 圆直径
		BALL_DIAMETER = 60;
		/**
		 * 默认颜色
		 */
		COLOR_UNIFORM = Color.argb(255, 255, 68, 68);
		/**
		 * 
		 */
		COLOR_IS_GRADIENT = true;
		/**
		 * 渐变色开始
		 */
		COLOR_GRADIENT_START = Color.argb(255, 153, 204, 0);
		/**
		 * 渐变色结束
		 */
		COLOR_GRADIENT_END = Color.argb(255, 255, 68, 68);

	}

	private void init() {
		this.setLayoutParams(
				new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

		switch (FORMAT) {
		case 0:
		case 1:
			this.setOrientation(VERTICAL);
			break;
		case 2:
		case 3:
			this.setOrientation(HORIZONTAL);
			break;
		}

		switch (VISUALIZER_GRAVITY) {
		case 0:
			this.setGravity(Gravity.CENTER);
			break;
		case 1:
			this.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
			break;
		case 2:
			this.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
			break;
		case 3:
			this.setGravity(Gravity.CENTER_VERTICAL | Gravity.END);
			break;
		case 4:
			this.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
			break;
		}

		this.addWaves();
	}

	private void addWaves() {
		params = new LinearLayout.LayoutParams(LINE_MIN_WIDTH, LINE_MIN_HEIGHT);
		params.setMargins(LINE_SPACING, 0, LINE_SPACING, 0);

		for (int i = 0; i < VISUALIZER_NUM_WAVES; i++) {
			View v = new View(context);
			v.setLayoutParams(params);
			this.setBackground(v);
			waveList.add(v);
			this.addView(v);
		}
	}

	private void setBackground(View v) {
		if (android.os.Build.VERSION.SDK_INT < 16)
			setBackgroundAPI15(v);
		else
			setBackgroundAPI16(v);
	}

	@SuppressLint("NewApi")
	@TargetApi(15)
	private void setBackgroundAPI15(View v) {
		GradientDrawable gd = null;

		if (COLOR_IS_GRADIENT) {
			switch (FORMAT) {
			case 0:
				gd = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,
						new int[] { COLOR_GRADIENT_START, COLOR_GRADIENT_END });
				gd.setGradientType(GradientDrawable.LINEAR_GRADIENT);
				break;
			case 2:
				gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
						new int[] { COLOR_GRADIENT_START, COLOR_GRADIENT_END });
				gd.setGradientType(GradientDrawable.LINEAR_GRADIENT);
				break;
			case 1:
				gd = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,
						new int[] { COLOR_GRADIENT_START, COLOR_GRADIENT_END });
				gd.setGradientType(GradientDrawable.OVAL);
				break;
			case 3:
				gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
						new int[] { COLOR_GRADIENT_START, COLOR_GRADIENT_END });
				gd.setGradientType(GradientDrawable.OVAL);
				break;
			}
		} else {
			gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
					new int[] { COLOR_UNIFORM, COLOR_UNIFORM });
		}

		gd.setCornerRadius(LINE_BORDER_RADIUS);
		gd.setGradientRadius(90.f);
		v.setBackground(gd);
	}

	@TargetApi(16)
	private void setBackgroundAPI16(View v) {
		GradientDrawable gd = new GradientDrawable();
		gd.setCornerRadius(LINE_BORDER_RADIUS);
		gd.setGradientRadius(90.f);

		if (COLOR_IS_GRADIENT) {
			gd.setColors(new int[] { COLOR_GRADIENT_START, COLOR_GRADIENT_END });

			switch (FORMAT) {
			case 0:
				gd.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
				break;
			case 2:
				gd.setOrientation(GradientDrawable.Orientation.TOP_BOTTOM);
				gd.setGradientType(GradientDrawable.LINEAR_GRADIENT);
				break;
			case 1:
				gd.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
				break;
			case 3:
				gd.setOrientation(GradientDrawable.Orientation.TOP_BOTTOM);
				gd.setGradientType(GradientDrawable.OVAL);
				break;
			}
		} else {
			gd.setColors(new int[] { COLOR_UNIFORM, COLOR_UNIFORM });
		}
		v.setBackground(gd);
	}

	@Override
	public void setFormat(int format) {
		this.FORMAT = format;
	}

	@Override
	public void setDimens(int width, int height) {
		this.VISUALIZER_WIDTH = width;
		this.VISUALIZER_HEIGHT = height;
	}

	@Override
	public void setWidth(int width) {
		this.VISUALIZER_WIDTH = width;
	}

	@Override
	public void setHeight(int height) {
		this.VISUALIZER_HEIGHT = height;
	}

	@Override
	public void setNumWaves(int waves) {
		this.VISUALIZER_NUM_WAVES = waves;
	}

	@Override
	public void setLineDimens(int width, int height) {
		this.LINE_WIDTH = width;
		this.LINE_HEIGHT = height;
	}

	@Override
	public void setLineWidth(int width) {
		this.LINE_WIDTH = width;
	}

	@Override
	public void setLineHeight(int height) {
		this.LINE_HEIGHT = height;
	}

	@Override
	public void setLineMinDimens(int minWidth, int minHeight) {
		this.LINE_MIN_WIDTH = minWidth;
		this.LINE_MIN_HEIGHT = minHeight;
	}

	@Override
	public void setLineMinWidth(int minWidth) {
		this.LINE_MIN_WIDTH = minWidth;
	}

	@Override
	public void setLineMinHeight(int minHeight) {
		this.LINE_MIN_HEIGHT = minHeight;
	}

	@Override
	public void setLineSpacing(int spacing) {
		this.LINE_SPACING = spacing;
	}

	@Override
	public void setLineBorderRadius(int borderRadius) {
		this.LINE_BORDER_RADIUS = borderRadius;
	}

	@Override
	public void setBallDiameter(int ballDiameter) {
		this.BALL_DIAMETER = ballDiameter;
	}

	@Override
	public void setColor(int color) {
		this.COLOR_UNIFORM = color;
	}

	@Override
	public void setIsGradient(boolean isGradient) {
		this.COLOR_IS_GRADIENT = isGradient;
	}

	@Override
	public void setGradient(int startColor, int endColor) {
		this.COLOR_GRADIENT_START = startColor;
		this.COLOR_GRADIENT_END = endColor;
	}

	@Override
	public void setGradientColorStart(int color) {
		this.COLOR_GRADIENT_START = color;
	}

	@Override
	public void setGradientColorEnd(int color) {
		this.COLOR_GRADIENT_END = color;
	}

	/**
	 * 开始录音
	 */
	public boolean startRecording(Activity activity, String path, boolean ifNew) {
		if (ifNew) {
			if (!AUDIO_PATH_TWO.equals("")) {
				File file = new File(AUDIO_PATH_TWO);
				if (file.exists()) {
					file.delete();
				}
				AUDIO_PATH_TWO = "";
			}
		}
		this.activity = activity;
		mstrPath = path;
		this.amrPath = mstrPath + "AUDIO_" + CameraUtils.getModifyTime() + STR_AMR;
		// 如果正在录音，则返回
		if (isRecording) {
			return isRecording;
		}
		// 初始化
		if (mMediaRecordFunc == null) {
			initRecorder();
		}
		
		mMediaRecordFunc.startRecordAndFile(amrPath);
	
		startBufferedWrite(mMediaRecordFunc.getmMediaRecorder());
	
		isRecording = true;
		return isRecording;
	}

	/**
	 * 停止录音，并且转换文件,<br/>
	 * <b>这很可能是个耗时操作，建议在后台中做
	 * 
	 * @return
	 */
	public boolean stopRecordingAndConvertFile() {
		if (!isRecording) {
			return isRecording;
		}
		// 停止
		mMediaRecordFunc.stopRecordAndFile();
		
		isRecording = false;
		// 开始转换
		AUDIO_PATH_ONE = amrPath;
		if (AUDIO_PATH_TWO.equals("")) {
			AUDIO_PATH_TWO = AUDIO_PATH_ONE;
		} else {
			AUDIO_PATH_THREE = mstrPath + "AUDIO_" + CameraUtils.getModifyTime() + STR_AMR;
			String[] path = { AUDIO_PATH_TWO, AUDIO_PATH_ONE };
			try {
				AudioUtils.megerCatch(path, AUDIO_PATH_THREE);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			AUDIO_PATH_TWO = AUDIO_PATH_THREE;
			// AudioUtils.mergeFiles4(path);
		}
		return isRecording;// convertOk==true,return true
	}

	public String getMp3Path() {
		return AUDIO_PATH_TWO;
	}

	// /**
	// * 开启下一次录音前，reset一下
	// *
	// * @param cleanFlag
	// */
	// public void reset(int cleanFlag) {
	// cleanFile(cleanFlag);
	// }

	/**
	 * 清理文件
	 * 
	 * @param cleanFlag
	 *            RAW,MP3 or RAW|MP3
	 */
	public void cleanFile() {
		try {
			File f = null;
			f = new File(amrPath);
			if (f.exists()) {
				f.delete();
			}
			f = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// -------内部的一些工具方法-------
	/**
	 * 初始化
	 */
	private void initRecorder() {
		mMediaRecordFunc = MediaRecordFunc.getInstance();
		mMediaRecordFunc.setMediaRecordFuncStater(this);
	}

	/**
	 * 写入到raw文件
	 * 
	 * @param file
	 */
	private void startBufferedWrite(final MediaRecorder recorder) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (isRecording) {
					// 平方和除以数据总长度，得到音量大小。
					// double mean = recorder.getMaxAmplitude() / (double) BASE;
					// double volume = 10 * Math.log10(mean);
					// int pitch = volume > 0 ? (int) volume : 1;

					int pitchInHz = 0;
					try {
						pitchInHz = recorder.getMaxAmplitude();
					} catch (RuntimeException e) {
						e.fillInStackTrace();
						pitchInHz = 0;
					}

					int pitch = pitchInHz > 100 ? (int) pitchInHz : 1;
					for (int i = 0; i < waveList.size(); i++) {
						// int random = randomNum.nextInt(10 - 1) + 1;
						// int size = pitch / random * 6;
						int random = randomNum.nextInt(10 - 1) + 1;
						int size = pitch / random / 20;
						switch (FORMAT) {
						case 0:
							params = new LinearLayout.LayoutParams(size < LINE_MIN_WIDTH ? LINE_MIN_WIDTH : size,
									LINE_HEIGHT);
							params.setMargins(0, LINE_SPACING, 0, LINE_SPACING);
							break;
						case 1:
							params = new LinearLayout.LayoutParams(size < LINE_MIN_WIDTH ? LINE_MIN_WIDTH : size / 2,
									size < LINE_MIN_HEIGHT ? LINE_MIN_HEIGHT : size / 2);
							params.setMargins(0, LINE_SPACING, 0, LINE_SPACING);
							break;
						case 2:
							params = new LinearLayout.LayoutParams(LINE_WIDTH,
									size < LINE_MIN_HEIGHT ? LINE_MIN_HEIGHT : size);
							params.setMargins(LINE_SPACING, 0, LINE_SPACING, 0);
							break;
						case 3:
							params = new LinearLayout.LayoutParams(size < LINE_MIN_WIDTH ? LINE_MIN_WIDTH : size / 2,
									size < LINE_MIN_HEIGHT ? LINE_MIN_HEIGHT : size / 2);
							params.setMargins(LINE_SPACING, 0, LINE_SPACING, 0);
							break;
						}
						Message msg = new Message();
						msg.what = INT_VISUALIZER;
						msg.arg2 = i + 1;
						msg.obj = params;
						uiThread.sendMessage(msg);
					}
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	public static String getSDPath(Context context, String pathName) {
		File sdDir = null;
		boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
		if (sdCardExist) {
			sdDir = Environment.getExternalStorageDirectory();
		} else if (!sdCardExist) {

			Toast.makeText(context, "SD卡不存在", Toast.LENGTH_SHORT).show();

		}
		File eis = new File(sdDir.toString() + "/" + pathName + "/");
		try {
			if (!eis.exists()) {
				eis.mkdir();
			}
		} catch (Exception e) {

		}
		return sdDir.toString() + "/" + pathName + "/";

	}

	@Override
	public void onMediaRecordFuncStart(long time) {
		mAudioStater.onAudioStart(time);
		
	}

	@Override
	public void onMediaRecordFuncStop(long time) {
		mAudioStater.onAudioStop(time);
		
	}
}
